Evaluating CLM Simulations at NEON Tower Sites – Tutorial – Interactive Plots¶
This tutorial provides a tool for interacive evaluations and analysis of CLM at NEON tower sites. This tool is based on Bokeh python package.
⚠️ Note: Before starting this tutorial, please make sure you successfully completed a simulation using the NEON_Simulation_Tutorial . Please use the same NEON site/sites here that you’ve already completed simulations for.
In this tutorial :
The notebook provide tools for interactive plotting and analysis of CLM at NEON tower sites. Below you will find steps to:
Create interactive app for showing tseries
Create interactive app for scatter plots and statitical summary
Please use the same NEON site/sites that you’ve already completed the simulations for.
neon_sites = ["ABBY","BART", "BLAN", "CPER", "DCFS","DSNY"]
#neon_site = neon_sites[0]
Please make sure that you’ve succesfully completed the CLM simulations for these sites. When a simulation completes, the data are transferred to the archive directory.
Similar to the previous tutorials, you can check the history output files in the archive folder.
!ls /Users/negins/Desktop/Simulations/archive/{neon_sites[0]}.transient/lnd/hist/*2018*.nc |head -20
/Users/negins/Desktop/Simulations/archive/ABBY.transient/lnd/hist/ABBY.transient.clm2.h0.2018-01.nc
/Users/negins/Desktop/Simulations/archive/ABBY.transient/lnd/hist/ABBY.transient.clm2.h0.2018-02.nc
/Users/negins/Desktop/Simulations/archive/ABBY.transient/lnd/hist/ABBY.transient.clm2.h0.2018-03.nc
/Users/negins/Desktop/Simulations/archive/ABBY.transient/lnd/hist/ABBY.transient.clm2.h0.2018-04.nc
/Users/negins/Desktop/Simulations/archive/ABBY.transient/lnd/hist/ABBY.transient.clm2.h0.2018-05.nc
/Users/negins/Desktop/Simulations/archive/ABBY.transient/lnd/hist/ABBY.transient.clm2.h0.2018-06.nc
/Users/negins/Desktop/Simulations/archive/ABBY.transient/lnd/hist/ABBY.transient.clm2.h0.2018-07.nc
/Users/negins/Desktop/Simulations/archive/ABBY.transient/lnd/hist/ABBY.transient.clm2.h0.2018-08.nc
/Users/negins/Desktop/Simulations/archive/ABBY.transient/lnd/hist/ABBY.transient.clm2.h0.2018-09.nc
/Users/negins/Desktop/Simulations/archive/ABBY.transient/lnd/hist/ABBY.transient.clm2.h0.2018-10.nc
/Users/negins/Desktop/Simulations/archive/ABBY.transient/lnd/hist/ABBY.transient.clm2.h0.2018-11.nc
/Users/negins/Desktop/Simulations/archive/ABBY.transient/lnd/hist/ABBY.transient.clm2.h0.2018-12.nc
/Users/negins/Desktop/Simulations/archive/ABBY.transient/lnd/hist/ABBY.transient.clm2.h1.2018-01-01-00000.nc
/Users/negins/Desktop/Simulations/archive/ABBY.transient/lnd/hist/ABBY.transient.clm2.h1.2018-01-02-00000.nc
/Users/negins/Desktop/Simulations/archive/ABBY.transient/lnd/hist/ABBY.transient.clm2.h1.2018-01-03-00000.nc
/Users/negins/Desktop/Simulations/archive/ABBY.transient/lnd/hist/ABBY.transient.clm2.h1.2018-01-04-00000.nc
/Users/negins/Desktop/Simulations/archive/ABBY.transient/lnd/hist/ABBY.transient.clm2.h1.2018-01-05-00000.nc
/Users/negins/Desktop/Simulations/archive/ABBY.transient/lnd/hist/ABBY.transient.clm2.h1.2018-01-06-00000.nc
/Users/negins/Desktop/Simulations/archive/ABBY.transient/lnd/hist/ABBY.transient.clm2.h1.2018-01-07-00000.nc
/Users/negins/Desktop/Simulations/archive/ABBY.transient/lnd/hist/ABBY.transient.clm2.h1.2018-01-08-00000.nc
1- Import Python Libraries¶
Run the below code to import the required python libraries for this notebook:
#Import Libraries
%matplotlib inline
import os
import sys
import time
import numpy as np
import pandas as pd
import xarray as xr
from glob import glob
from os.path import join, expanduser
import matplotlib
import matplotlib.pyplot as plt
from scipy import stats
from neon_utils import download_eval_files
#Specify the year
year = "2018"
2- Load Pre-processed data:¶
df_list =[]
for neon_site in neon_sites[0:2]:
pkl_dir = '/Users/negins/Desktop/Simulations/tutorials/processed_data'
pkl_name = neon_site+'_'+year+'df_all.pkl'
processed_data = os.path.join(pkl_dir,pkl_name)
df_all = pd.read_pickle(processed_data).reset_index()
df_all['site']=neon_site
df_list.append(df_all)
df_all_sites = pd.concat(df_list)
print (df_all_sites)
print (df_all_sites[df_all_sites['site']=='ABBY'])
index time NEE FSH EFLX_LH_TOT GPP \
0 0 2018-01-01 00:00:00 1.592983 -6.384231 7.999955 NaN
1 1 2018-01-01 00:30:00 1.180044 -19.939597 9.523534 NaN
2 2 2018-01-01 01:00:00 0.975515 -16.453217 9.358360 NaN
3 3 2018-01-01 01:30:00 0.260440 -1.420895 5.013022 NaN
4 4 2018-01-01 02:00:00 2.474247 -4.324410 2.368721 NaN
... ... ... ... ... ... ...
17515 17515 2018-12-31 21:30:00 -1.981586 -3.769276 0.499174 NaN
17516 17516 2018-12-31 22:00:00 -1.981586 -6.985562 0.194687 NaN
17517 17517 2018-12-31 22:30:00 -1.947493 -2.467863 -0.841958 NaN
17518 17518 2018-12-31 23:00:00 -2.057455 0.689793 0.356680 NaN
17519 17519 2018-12-31 23:30:00 -1.947493 1.180507 -0.026794 NaN
Rnet sim_FCEV sim_FCTR sim_FGEV ... sim_AR \
0 -49.70 -7.638256e+00 1.545730e-16 6.177156 ... 1.796636e-05
1 -64.01 -9.999990e+00 0.000000e+00 8.121943 ... 2.111855e-05
2 -67.15 -8.272110e+00 0.000000e+00 7.193620 ... 2.045357e-05
3 -62.43 -7.173703e+00 0.000000e+00 6.415617 ... 2.017028e-05
4 -67.24 -7.002048e+00 0.000000e+00 6.262212 ... 1.964822e-05
... ... ... ... ... ... ...
17515 -28.58 1.027028e-07 0.000000e+00 0.144563 ... 9.833552e-07
17516 -8.33 -1.377483e-08 9.712527e-17 0.036043 ... 9.832469e-07
17517 -6.71 1.069803e-05 0.000000e+00 8.786987 ... 9.747794e-07
17518 -5.18 3.430142e-07 3.363154e-17 0.141638 ... 9.628571e-07
17519 -1.90 NaN NaN NaN ... NaN
sim_HR sim_EFLX_LH_TOT sim_Rnet sim_NEE year month day hour \
0 0.000026 -1.461100 -44.383476 -0.000015 2018 1 1 0
1 0.000025 -1.878047 -55.759464 -0.000046 2018 1 1 0
2 0.000025 -1.078490 -57.324272 -0.000046 2018 1 1 1
3 0.000025 -0.758087 -53.428955 -0.000045 2018 1 1 1
4 0.000025 -0.739836 -57.476784 -0.000044 2018 1 1 2
... ... ... ... ... ... ... ... ...
17515 0.000002 0.144563 -33.488106 -0.000003 2018 12 31 21
17516 0.000002 0.036043 -12.458500 -0.000003 2018 12 31 22
17517 0.000002 8.786998 -10.466762 -0.000003 2018 12 31 22
17518 0.000002 0.141638 -9.539567 -0.000003 2018 12 31 23
17519 NaN NaN NaN NaN 2018 12 31 23
site
0 ABBY
1 ABBY
2 ABBY
3 ABBY
4 ABBY
... ...
17515 BART
17516 BART
17517 BART
17518 BART
17519 BART
[35040 rows x 24 columns]
index time NEE FSH EFLX_LH_TOT GPP \
0 0 2018-01-01 00:00:00 1.592983 -6.384231 7.999955 NaN
1 1 2018-01-01 00:30:00 1.180044 -19.939597 9.523534 NaN
2 2 2018-01-01 01:00:00 0.975515 -16.453217 9.358360 NaN
3 3 2018-01-01 01:30:00 0.260440 -1.420895 5.013022 NaN
4 4 2018-01-01 02:00:00 2.474247 -4.324410 2.368721 NaN
... ... ... ... ... ... ...
17515 17515 2018-12-31 21:30:00 -3.305683 53.417014 127.891286 NaN
17516 17516 2018-12-31 22:00:00 -2.321932 24.107347 6.909593 NaN
17517 17517 2018-12-31 22:30:00 -1.665410 35.354257 -0.758793 NaN
17518 17518 2018-12-31 23:00:00 -3.370616 -0.794320 -2.582525 NaN
17519 17519 2018-12-31 23:30:00 -1.899204 -1.785594 -6.315270 NaN
Rnet sim_FCEV sim_FCTR sim_FGEV ... sim_AR sim_HR \
0 -49.70 -7.638256 1.545730e-16 6.177156 ... 0.000018 0.000026
1 -64.01 -9.999990 0.000000e+00 8.121943 ... 0.000021 0.000025
2 -67.15 -8.272110 0.000000e+00 7.193620 ... 0.000020 0.000025
3 -62.43 -7.173703 0.000000e+00 6.415617 ... 0.000020 0.000025
4 -67.24 -7.002048 0.000000e+00 6.262212 ... 0.000020 0.000025
... ... ... ... ... ... ... ...
17515 280.43 37.526901 8.447243e+00 0.421997 ... 0.000022 0.000026
17516 235.71 36.608852 7.772662e+00 0.761458 ... 0.000021 0.000026
17517 185.06 31.220009 7.147894e+00 0.631587 ... 0.000021 0.000026
17518 127.01 25.218470 5.901747e+00 0.661987 ... 0.000021 0.000026
17519 70.92 NaN NaN NaN ... NaN NaN
sim_EFLX_LH_TOT sim_Rnet sim_NEE year month day hour site
0 -1.461100 -44.383476 -0.000015 2018 1 1 0 ABBY
1 -1.878047 -55.759464 -0.000046 2018 1 1 0 ABBY
2 -1.078490 -57.324272 -0.000046 2018 1 1 1 ABBY
3 -0.758087 -53.428955 -0.000045 2018 1 1 1 ABBY
4 -0.739836 -57.476784 -0.000044 2018 1 1 2 ABBY
... ... ... ... ... ... ... ... ...
17515 46.396141 259.828949 0.000015 2018 12 31 21 ABBY
17516 45.142975 218.192841 0.000012 2018 12 31 22 ABBY
17517 38.999493 167.951035 0.000011 2018 12 31 22 ABBY
17518 31.782204 110.927956 0.000007 2018 12 31 23 ABBY
17519 NaN NaN NaN 2018 12 31 23 ABBY
[17520 rows x 24 columns]
df_all = df_all_sites
#-- extract year, month, day, hour information from time
df_all['year'] = df_all['time'].dt.year
df_all['month'] = df_all['time'].dt.month
df_all['day'] = df_all['time'].dt.day
df_all['hour'] = df_all['time'].dt.hour
3) Time-Series Visualization¶
3.1) Time-Series Dashboard with Scatterplots¶
#time-series with Dropdown menu for values
from scipy import stats
import yaml
from bokeh.themes import Theme
from bokeh.models import ColumnDataSource, Slider , Dropdown, Select, PreText, Label, Slope
from bokeh.layouts import row,column
# make a simple plot time-series
from bokeh.io import output_notebook, show
from bokeh.plotting import figure
from bokeh.models import ColumnDataSource, HoverTool
from neon_bokeh_utils import simple_tseries
import os
os.environ['BOKEH_RESOURCES'] = 'inline'
from bokeh.resources import INLINE
import bokeh.io
from bokeh import *
bokeh.io.output_notebook(INLINE)
#time-series with Dropdown menu for values
from scipy import stats
import yaml
from bokeh.themes import Theme
from bokeh.models import ColumnDataSource, Slider , Dropdown, Select, PreText, Label, Slope
from bokeh.layouts import row,column
# make a simple plot time-series
from bokeh.io import output_notebook, show
from bokeh.plotting import figure
from bokeh.models import ColumnDataSource, HoverTool
#from neon_bokeh_utils import simple_tseries
import os
os.environ['BOKEH_RESOURCES'] = 'inline'
from bokeh.resources import INLINE
import bokeh.io
from bokeh import *
bokeh.io.output_notebook(INLINE)
freq_list = ['all','hourly','daily','monthly']
def get_data (df, var, freq, site):
df[df['site']==neon_site]
#var_name = var
sim_var_name = "sim_"+var
#print (var)
#print (sim_var_name)
if freq=="monthly":
df = df.groupby(['year','month']).mean().reset_index()
df["day"]=15
df['time']=pd.to_datetime(df[["year", "month","day"]])
elif freq=="daily":
df = df.groupby(['year','month','day']).mean().reset_index()
df['time']=pd.to_datetime(df[["year", "month", "day"]])
elif freq=="hourly" or freq=="all":
df = df.groupby(['year','month','day','hour']).mean().reset_index()
df['time']=pd.to_datetime(df[["year", "month", "day","hour"]])
df_new = pd.DataFrame({'time':df['time'],'NEON':df[var],'CLM':df[sim_var_name]})
#print(df_new)
return df_new
def find_regline(df, var, sim_var_name):
# find the trendline:
#sim_var_name = "sim_"+var
#print (var)
#print (sim_var_name)
df_temp = df[[var, sim_var_name]]#.dropna()
#df_temp = pd.DataFrame(df, columns)
df_temp.dropna(inplace=True)
#print (df_temp)
#z = np.polyfit(df_temp[var], df_temp[sim_var_name], 1)
#p = np.poly1d(z)
#-----
slope, intercept, r_value, p_value, std_err = stats.linregress(df_temp[var], df_temp[sim_var_name])
return slope, intercept, r_value, p_value, std_err
plot_vars =['FSH','EFLX_LH_TOT','Rnet','NEE','GPP']
def simple_tseries(doc):
df_new = get_data(df_all, 'EFLX_LH_TOT','hourly','ABBY')
source = ColumnDataSource(df_new)
#-- what are tools options
tools = "hover, box_zoom, undo, crosshair"
p = figure(tools=tools, x_axis_type="datetime", title= "Neon Time-Series "+neon_site)
p.line('time', 'NEON', source=source, alpha=0.8, line_width=4, color="navy", legend_label="NEON")
p.line('time', 'CLM',source=source , alpha=0.8, line_width=3, color="red", legend_label="CLM")
#p.circle('time', 'var', source=source, alpha=0.8, color="navy")
p.xaxis.major_label_text_color = 'dimgray'
p.xaxis.major_label_text_font_size = '15px'
p.yaxis.major_label_text_color = 'dimgray'
p.yaxis.major_label_text_font_size = '15px'
p.xaxis.axis_label_text_font_size = "15pt"
p.axis.axis_label_text_font_style = "bold"
p.grid.grid_line_alpha = 0.5
p.title.text_font_size = '15pt'
p.xaxis.axis_label = 'Time'
def scatter_plot(q):
q.circle('NEON', 'CLM', source=source, alpha=0.8, color="navy",fill_alpha=0.2, size=10)
q.xaxis.major_label_text_color = 'dimgray'
q.xaxis.major_label_text_font_size = '15px'
q.yaxis.major_label_text_color = 'dimgray'
q.yaxis.major_label_text_font_size = '15px'
q.xaxis.axis_label_text_font_size = "13pt"
q.yaxis.axis_label_text_font_size = "13pt"
q.axis.axis_label_text_font_style = "bold"
q.grid.grid_line_alpha = 0.5
q.title.text_font_size = '15pt'
q.xaxis.axis_label = 'NEON'
q.yaxis.axis_label = 'CLM'
#x = range(0,500)
#y = range(0,500)
#q.line(x, y,alpha=0.8, line_width=4, color="gray")
q_width = 350
q_height = 350
q = figure(tools=tools,width=350, height=350)
scatter_plot(q)
p.add_tools(
HoverTool(
tooltips=[('value','@value{2.2f}'),
('index', '@index')]
)
)
stats = PreText(text='', width=500)
menu = Select(options=plot_vars,value='EFLX_LH_TOT', title='Variable')
def update_variable (attr, old, new):
#print (menu.value)
#print (menu_freq.value)
df_new = get_data(df_all, menu.value, menu_freq.value, menu_site.value)
#slope, intercept, r_value, p_value, std_err = find_regline(df_new, 'NEON','CLM')
#print (r_value)
#slope_label = "y="+"{:.2f}".format(slope)+"+"+"{:.2f}".format(intercept)+"x"+" (R2="+"{:.2f}".format(r_value)+")"
#mytext = Label(text=slope_label , x=0+20, y=q_height-100,
# x_units="screen", y_units='screen', text_align="left")
#regression_line = Slope(gradient=slope, y_intercept=intercept, line_color="red")
#print(slope_label)
#q.add_layout(mytext)
#q.add_layout(regression_line)
source.data =df_new
#source.stream(df_new)
def update_site (attr, old, new):
p.title.text = "Neon Time-Series " +menu_site.value
menu.on_change('value', update_variable)
menu_freq = Select(options=freq_list,value='all', title='Frequency')
menu_freq.on_change('value', update_variable)
menu_site = Select(options=neon_sites,value='ABBY', title='Neon Site')
menu_site.on_change('value', update_site)
#layout = row(column(menu, menu_freq, menu_site, q), p)
layout = row(p, column( menu, menu_freq, menu_site, q))
doc.add_root(layout)
doc.theme = Theme(json=yaml.load("""
attrs:
Figure:
background_fill_color: "#FFFFFF"
outline_line_color: white
toolbar_location: above
height: 550
width: 1100
Grid:
grid_line_dash: [6, 4]
grid_line_color: gray
""", Loader=yaml.FullLoader))
3.2) Time-Series DashBoard with Statistics¶
def stats_tseries(doc):
df_new = get_data(df_all, 'EFLX_LH_TOT','hourly','ABBY')
source = ColumnDataSource(df_new)
#-- what are tools options
tools = "hover, box_zoom, undo, crosshair"
def timeseries_plot (p):
p.line('time', 'NEON', source=source, alpha=0.8, line_width=4, color="navy", legend_label="NEON")
p.line('time', 'CLM',source=source , alpha=0.8, line_width=3, color="red", legend_label="CLM")
#p.circle('time', 'var', source=source, alpha=0.8, color="navy")
p.xaxis.major_label_text_color = 'dimgray'
p.xaxis.major_label_text_font_size = '15px'
p.yaxis.major_label_text_color = 'dimgray'
p.yaxis.major_label_text_font_size = '15px'
p.xaxis.axis_label_text_font_size = "15pt"
p.axis.axis_label_text_font_style = "bold"
p.grid.grid_line_alpha = 0.5
p.title.text_font_size = '15pt'
p.xaxis.axis_label = 'Time'
def scatter_plot(q):
q.circle('NEON', 'CLM', source=source, alpha=0.8, color="navy",fill_alpha=0.2, size=10)
print (df_new)
q.xaxis.major_label_text_color = 'dimgray'
q.xaxis.major_label_text_font_size = '15px'
q.yaxis.major_label_text_color = 'dimgray'
q.yaxis.major_label_text_font_size = '15px'
q.xaxis.axis_label_text_font_size = "13pt"
q.yaxis.axis_label_text_font_size = "13pt"
q.axis.axis_label_text_font_style = "bold"
q.grid.grid_line_alpha = 0.5
q.title.text_font_size = '15pt'
q.xaxis.axis_label = 'NEON'
q.yaxis.axis_label = 'CLM'
slope, intercept, r_value, p_value, std_err = find_regline(df_new, 'NEON','CLM')
#print (r_value)
slope_label = "y="+"{:.2f}".format(slope)+"+"+"{:.2f}".format(intercept)+"x"+" (R2="+"{:.2f}".format(r_value)+")"
mytext = Label(text=slope_label , x=0+20, y=q_height-100,
x_units="screen", y_units='screen', text_align="left")
regression_line = Slope(gradient=slope, y_intercept=intercept, line_color="red")
#q.add_layout(mytext)
q.add_layout(regression_line)
print ("slope_label:", slope_label)
q.title.text = slope_label
#x = range(0,500)
#y = range(0,500)
#q.line(x, y,alpha=0.8, line_width=4, color="gray")
p = figure(tools=tools, x_axis_type="datetime", title= "Neon Time-Series "+neon_site)
timeseries_plot(p)
q_width = 350
q_height= 350
q = figure(tools=tools,width=q_width, height=q_height)
scatter_plot(q)
p.add_tools(
HoverTool(
tooltips=[('value','@value{2.2f}'),
('index', '@index')]))
def update_variable (attr, old, new):
#print (menu.value)
#print (menu_freq.value)
df_new = get_data(df_all, menu.value, menu_freq.value, menu_site.value)
#print ("=======================================")
#print ("Statistics summary for var: "+menu.value)
#print (df_new.describe())
#print ("----------------")
#print(slope_label)
#print ("R2 = "+"{:.2f}".format(r_value))
#print ("p-value = "+"{:.2f}".format(p_value))
#print ("std-err = "+"{:.1f}".format(p_value))
#print ("=======================================")
#source.data =df_new
source.data.update(df_new)
#scatter_plot(q)
#source.stream(df_new)
#slope, intercept, r_value, p_value, std_err = find_regline(df_new, 'NEON','CLM')
#print (r_value)
#slope_label = "y="+"{:.2f}".format(slope)+"+"+"{:.2f}".format(intercept)+"x"+" (R2="+"{:.2f}".format(r_value)+")"
#mytext = Label(text=slope_label , x=0+20, y=q_height-100,
# x_units="screen", y_units='screen', text_align="left")
#regression_line = Slope(gradient=slope, y_intercept=intercept, line_color="red")
#q.add_layout(mytext)
#print (q)
#q.title.text = slope_label
#q.add_layout(regression_line)
#print ("slope_label:", slope_label)
slope, intercept, r_value, p_value, std_err = find_regline(df_new, 'NEON','CLM')
#print (r_value)
slope_label = "y="+"{:.2f}".format(slope)+"+"+"{:.2f}".format(intercept)+"x"+" (R2="+"{:.2f}".format(r_value)+")"
mytext = Label(text=slope_label , x=0+20, y=q_height-100,
x_units="screen", y_units='screen', text_align="left")
regression_line = Slope(gradient=slope, y_intercept=intercept, line_color="red")
#q.add_layout(mytext)
print ("slope_label:", slope_label)
q.title.text = slope_label
def update_site (attr, old, new):
p.title.text = "Neon Time-Series " +menu_site.value
menu = Select(options=plot_vars,value='EFLX_LH_TOT', title='Variable')
menu.on_change('value', update_variable)
menu_freq = Select(options=freq_list,value='all', title='Frequency')
menu_freq.on_change('value', update_variable)
menu_site = Select(options=neon_sites,value='HARV', title='Neon Site')
menu_site.on_change('value', update_site)
#layout = row(column(menu, menu_freq, menu_site, q), p)
layout = row(p, column( menu, menu_freq, menu_site, q))
doc.add_root(layout)
doc.theme = Theme(json=yaml.load("""
attrs:
Figure:
background_fill_color: "#FFFFFF"
outline_line_color: white
toolbar_location: above
height: 550
width: 1100
Grid:
grid_line_dash: [6, 4]
grid_line_color: gray
""", Loader=yaml.FullLoader))
output_notebook()
show(stats_tseries)
time NEON CLM
0 2018-01-01 00:00:00 6.771990 10.186131
1 2018-01-01 01:00:00 6.005897 11.059019
2 2018-01-01 02:00:00 2.491490 11.179670
3 2018-01-01 03:00:00 0.852504 9.580622
4 2018-01-01 04:00:00 1.275915 8.094493
... ... ... ...
8755 2018-12-31 19:00:00 0.063862 16.354586
8756 2018-12-31 20:00:00 29.076470 18.078854
8757 2018-12-31 21:00:00 38.215214 21.416418
8758 2018-12-31 22:00:00 1.375882 23.241377
8759 2018-12-31 23:00:00 -2.141977 15.961921
[8760 rows x 3 columns]
slope_label: y=0.76+8.60x (R2=0.90)
/usr/local/Caskroom/miniconda/base/envs/neon3/lib/python3.9/site-packages/pandas/util/_decorators.py:311: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
return func(*args, **kwargs)
Congratulations! You have:¶
Created two time-seires dashboard for analyzing neon data.